package com.acegear.horizon.controllers;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;

import org.hibernate.SQLQuery;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import scala.annotation.meta.setter;

import com.acegear.horizon.controllers.vo.ResultVO;
import com.acegear.horizon.domain.models.Post;
import com.acegear.horizon.domain.models.jpa.ContentPart;
import com.acegear.horizon.domain.repository.PostRepository;
import com.acegear.horizon.domain.repository.UserRepository;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

/**
 * Created by wangsike on 2016/12/23.
 */
@RestController
@RequestMapping("/posts")
public class PostController {
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PostRepository postRepository;

    @Autowired
    EntityManagerFactory emf = null;
    
    @RequestMapping(value = "", method = RequestMethod.POST)
    public ResultVO postTo(@RequestBody PostBody postBody,
                           @RequestHeader(value = "X-Consumer-Username") Long userId) {
        return userRepository
                .findByUserId(userId)
                .map(user -> user
                        .postTo(postBody.getClubId(), postBody.getType(), postBody.getContents())
                        .getUserPostVO(userId))
                .map(ResultVO::new).orElse(ResultVO.POST_SEND_FAILED);
    }

    @RequestMapping(value = "/{postId}/like", method = RequestMethod.POST)
    public ResultVO like(@PathVariable Long postId,
                         @RequestHeader(value = "X-Consumer-Username") Long userId) {
        return postRepository
                .findByPostId(postId)
                .filter(post -> post.like(userId))
                .map(post -> {
                    Map<String, Integer> result = new HashMap<>();
                    result.put("likeCount", post.getLikeCount());
                    return new ResultVO<>(result);
                })
                .orElse(ResultVO.POST_LIKE_FAILED);
    }

    @RequestMapping(value = "/{postId}/like", method = RequestMethod.DELETE)
    @Transactional
    public ResultVO unlike(@PathVariable Long postId,
                           @RequestHeader(value = "X-Consumer-Username") Long userId) {
        return postRepository
                .findByPostId(postId)
                .filter(post -> post.unlike(userId))
                .map(post -> {
                    Map<String, Integer> result = new HashMap<>();
                    result.put("likeCount", post.getLikeCount());
                    return new ResultVO<>(result);
                })
                .orElse(ResultVO.POST_LIKE_FAILED);
    }

    @RequestMapping(value = "/{postId}", method = RequestMethod.GET)
    public ResultVO post(@PathVariable Long postId,
                         @RequestHeader(value = "X-Consumer-Username", required = false, defaultValue = "0") Long viewerId) {
        return postRepository.findByPostId(postId)
                .map(post -> post.getUserPostVO(viewerId))
                .map(ResultVO::new)
                .orElse(ResultVO.POST_NOT_FOUND);
    }

    @RequestMapping(value = "/{postId}", method = RequestMethod.DELETE)
    public ResultVO deletePost(@PathVariable Long postId,
                               @RequestHeader(value = "X-Consumer-Username") Long userId,String rank) {
        return postRepository
                .findByPostId(postId)
                .filter(post -> post.deletePost(rank))
                .map(post -> {
                    Map<String, Boolean> result = new HashMap<>();
                    result.put("success", true);
                    return new ResultVO<>(result);
                })
                .orElse(ResultVO.POST_DELETE_FAILED);
    }

    @RequestMapping(value = "/{postId}/comments", method = RequestMethod.POST)
    public ResultVO comment(@PathVariable Long postId,
                            @RequestHeader(value = "X-Consumer-Username") Long userId,
                            @RequestBody(required = false) CommentBody commentBody) {
        return postRepository.findByPostId(postId)
                .flatMap(post -> post.comment(userId, commentBody.getReplyTo(), commentBody.getContents()))
                .map(ResultVO::new)
                .orElse(ResultVO.POST_NOT_FOUND);
    }


    @RequestMapping(value = "/{postId}/comments/{commentId}", method = RequestMethod.DELETE)
    public ResultVO deletePostComment(@PathVariable Long postId, @PathVariable Long commentId,
                                      @RequestHeader(value = "X-Consumer-Username") Long userId) {
        return postRepository
                .findByPostId(postId)
                .filter(post -> post.deleteComment(commentId, userId))
                .map(post -> {
                    Map<String, Boolean> result = new HashMap<>();
                    result.put("success", true);
                    return new ResultVO<>(result);
                })
                .orElse(ResultVO.POSTCOMMENT_DELETE_FAILED);
    }

    @RequestMapping(value = "/{postId}/comments/{commentId}", method = RequestMethod.GET)
    public ResultVO queryPostComment(@PathVariable Long postId, @PathVariable Long commentId) {
        return postRepository
                .findByPostId(postId)
                .map(post -> post.getComments(commentId))
                .map(ResultVO::new)
                 .orElse(ResultVO.POST_NOT_FOUND);
    }


    @RequestMapping(value = "/{postId}/comments", method = RequestMethod.GET)
    public ResultVO getComments(@PathVariable Long postId, Integer page, Integer count) {
        PageRequest pageRequest = new PageRequest(page, count);
        return postRepository.findByPostId(postId)
                .map(post -> post.getComments(pageRequest))
                .map(ResultVO::new)
                .orElse(ResultVO.POST_NOT_FOUND);
    }

    @RequestMapping(value = "/{postId}/report", method = RequestMethod.POST)
    public ResultVO reportPost(@PathVariable Long postId,
                               @RequestHeader(value = "X-Consumer-Username") Long userId) {
        return postRepository.findByPostId(postId)
                .map(post -> post.report(userId))
                .map(ResultVO::new)
                .orElse(ResultVO.POST_NOT_FOUND);
    }
    @RequestMapping(value = "/findPostDetail", method = RequestMethod.GET)
    public ResultVO findPostDetail( Long postId,Long viewerId) {
        return postRepository.findByPostId(postId)
                .map(post -> post.getUserPostVO(viewerId))
                .map(ResultVO::new)
                .orElse(ResultVO.POST_NOT_FOUND);
    }
    /**
     * 删除帖子
     * @param postId
     * @param userId
     * @return
     */
    @Transactional
    @RequestMapping( value = "/deletePost" )
    public ResultVO findPostcomment(Long postId,Long userId,String rank){
    	 return postRepository
                 .findByPostId(postId)
                 .filter(post -> post.deletePost(rank))
                 .map(post -> {
                     Map<String, Boolean> result = new HashMap<>();
                     result.put("success", true);
                     return new ResultVO<>(result);
                 })
                 .orElse(ResultVO.POST_DELETE_FAILED);
    }
    
    @RequestMapping(value = "/findPostComment", method = RequestMethod.GET)
    public ResultVO findPostcomment(Integer page,Integer count,Long clubId){
    	StringBuffer sb = new StringBuffer();
    	sb.append(" SELECT  u.postId, u.contents, u.userId, IFNULL(t.commentCount,0) commentCount, IFNULL(t1.likeCount,0) likeCount, t2.content, u.createAt,ui.nickname, 0  readCount ");
    	sb.append(" FROM userpost u  LEFT JOIN userinfo ui ON u.userId = ui.userId LEFT JOIN( SELECT  count(*) commentCount, p.postId FROM postcomment p  ) t ON t.postId = u.postId ");
    	sb.append(" LEFT JOIN( SELECT  COUNT(*) likeCount, l.postId FROM postlike l  ) t1 ON t1.postId = u.postId ");
    	sb.append(" LEFT JOIN ( SELECT c.content,c.pos  FROM contentpart c  ) t2 ON t2.pos= u.postId WHERE u.deleted = 0 AND u.clubId = "+clubId+" LIMIT "+page+","+count+"");

    	EntityManager em = emf.createEntityManager();   
    	
    	Query query = em.createNativeQuery(sb.toString());
    	
    	query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);  
    	List list = query.getResultList();
    	
    	StringBuffer sbSum = new StringBuffer();
    	sbSum.append(" SELECT  u.postId, u.contents, u.userId, IFNULL(t.commentCount,0) commentCount, IFNULL(t1.likeCount,0) likeCount, t2.content, u.createAt,ui.nickname, 0 readCount ");
    	sbSum.append(" FROM userpost u  LEFT JOIN userinfo ui ON u.userId = ui.userId LEFT JOIN( SELECT  count(*) commentCount, p.postId FROM postcomment p  ) t ON t.postId = u.postId ");
    	sbSum.append(" LEFT JOIN( SELECT  COUNT(*) likeCount, l.postId FROM postlike l  ) t1 ON t1.postId = u.postId ");
    	sbSum.append(" LEFT JOIN ( SELECT c.content,c.pos  FROM contentpart c  ) t2 ON t2.pos= u.postId WHERE u.deleted = 0 AND u.clubId = "+clubId+"");

    	Query querySum = em.createNativeQuery(sbSum.toString());
    	
    	querySum.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);  
    	List listSum = querySum.getResultList();
    	
    	Map<String,Object> map = new HashMap<String, Object>();
    	map.put("count", listSum.size());
    	map.put("postList", list);
    	return new ResultVO<>(map);
    	
    }
   
    @RequestMapping(value = "/findPostReportList", method = RequestMethod.GET)
    public ResultVO findPostReportList(Integer page,Integer count,Long clubId){
    	EntityManager em = emf.createEntityManager();   
    	
    	StringBuffer sb = new StringBuffer();
    	sb.append(" SELECT t3.postId, t3.contents, t3.userId, IFNULL(t.commentCount, 0) commentCount, IFNULL(t1.likeCount, 0) likeCount, t2.content, t3.createAt FROM report r ");
    	sb.append(" LEFT JOIN ( SELECT COUNT(*) commentCount, p.postId FROM postcomment p ) t ON t.postId = r.targetId ");
    	sb.append(" LEFT JOIN ( SELECT COUNT(*) likeCount, l.postId FROM postlike l ) t1 ON t1.postId = r.targetId ");
    	sb.append(" LEFT JOIN ( SELECT c.content, c.pos FROM contentpart c ) t2 ON t2.pos = r.targetId ");
    	sb.append(" LEFT JOIN ( SELECT u.userId, u.contents, u.postId, u.createAt, u.deleted FROM userpost u ) t3 ON t3.userId = r.targetId ");
    	sb.append(" WHERE t3.deleted = 0 LIMIT "+page+","+count+"");
    	
    	Query query = em.createNativeQuery(sb.toString());
    	
    	query.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);  
    	List list = query.getResultList();
    	
    	StringBuffer sbSum = new StringBuffer();
    	sbSum.append(" SELECT t3.postId, t3.contents, t3.userId, IFNULL(t.commentCount, 0) commentCount, IFNULL(t1.likeCount, 0) likeCount, t2.content, t3.createAt FROM report r ");
    	sbSum.append(" LEFT JOIN ( SELECT COUNT(*) commentCount, p.postId FROM postcomment p ) t ON t.postId = r.targetId ");
    	sbSum.append(" LEFT JOIN ( SELECT COUNT(*) likeCount, l.postId FROM postlike l ) t1 ON t1.postId = r.targetId ");
    	sbSum.append(" LEFT JOIN ( SELECT c.content, c.pos FROM contentpart c ) t2 ON t2.pos = r.targetId ");
    	sbSum.append(" LEFT JOIN ( SELECT u.userId, u.contents, u.postId, u.createAt, u.deleted FROM userpost u ) t3 ON t3.userId = r.targetId ");
    	sbSum.append(" WHERE t3.deleted = 0 ");
    	
    	Query querySum = em.createNativeQuery(sbSum.toString());
    	
    	querySum.unwrap(SQLQuery.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);  
    	List listSum = querySum.getResultList();
    	Map<String,Object> map = new HashMap<String, Object>();
    	map.put("count", listSum.size());
    	map.put("postList", list);
    	
    	return new ResultVO<>(map);
    }
}

@JsonIgnoreProperties(ignoreUnknown = true)
class PostBody {
    private Long clubId;
    private Integer type;
    private List<ContentPart> contents;

    public Long getClubId() {
        return clubId;
    }

    public void setClubId(Long clubId) {
        this.clubId = clubId;
    }

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public List<ContentPart> getContents() {
        return contents;
    }

    public void setContents(List<ContentPart> contents) {
        this.contents = contents;
    }
}

@JsonIgnoreProperties(ignoreUnknown = true)
class CommentBody {
    private Long replyTo;

    private List<ContentPart> contents;

    public Long getReplyTo() {
        return replyTo;
    }

    public void setReplyTo(Long replyTo) {
        this.replyTo = replyTo;
    }

    public List<ContentPart> getContents() {
        return contents;
    }

    public void setContents(List<ContentPart> contents) {
        this.contents = contents;
    }
}